package com.ruoyi.caiwu.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.caiwu.domain.*;
import com.ruoyi.caiwu.enums.BalanceTypeEnum;
import com.ruoyi.caiwu.enums.ClearingConfirmStateEnum;
import com.ruoyi.caiwu.enums.DzStateEnum;
import com.ruoyi.caiwu.enums.OperationTypeEnum;
import com.ruoyi.caiwu.service.*;
import com.ruoyi.caiwu.mapper.CwClearingMapper;
import com.ruoyi.caiwu.utils.BigdecimalUtils;
import com.ruoyi.common.core.exception.BusinessException;
import com.ruoyi.common.security.service.TokenService;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
* @author 86182
* @description 针对表【t_cw_clearing(结算表)】的数据库操作Service实现
* @createDate 2023-05-04 14:38:01
*/
@Log
@Service
public class CwClearingServiceImpl extends ServiceImpl<CwClearingMapper, CwClearing>
    implements CwClearingService{

    @Autowired
    CwPayOrderDetailService cwPayOrderDetailService;

    @Autowired
    CwBalanceService cwBalanceService;

    @Autowired
    MCompanyAccountService companyAccountService;

    @Autowired
    TokenService tokenService;

    @Autowired
    CwCztxApplyService cwCztxApplyService;

    @Autowired
    CwPayOrderService cwPayOrderService;

    @Override
    public List<CwClearing> settlementManagement(String checkBatchNo) {
        return this.baseMapper.settlementManagement(checkBatchNo);
    }

    @Override
    public void confirmClearing(List<Long> clearingIdList) {
        log.info("confirmClearing确认结算处理 Start...");

        if (clearingIdList == null || clearingIdList.size() == 0) {

            log.warning("----结算对象数据无。");
            throw new BusinessException("未选择待结算数据。");
        }

        log.warning("----结算对象数据共"+clearingIdList.size()+"条。");

        // 循环处理每一个结算记录
        for (Long clearingItemId : clearingIdList) {

            log.info("--------当前处理结算ID："+clearingItemId);

            // 1、************ 获取对应结算记录
            CwClearing clearing = this.baseMapper.selectById(clearingItemId);

            if (clearing == null || StringUtils.isBlank(clearing.getPayOrderNo())) {
                log.warning("--------结算记录查询无。");
                continue;
            }

            // 2、************ 根据结算记录中的支付订单号查询对应的支付订单明细，
            //    并且进行业务订单金额的商户入账更新操作
            CwPayOrderDetail queryOption = new CwPayOrderDetail();
            // 支付订单No
            queryOption.setPayOrderNo(clearing.getPayOrderNo());
            queryOption.setDelFlg(0);

            QueryWrapper<CwPayOrderDetail> queryWrapper = new QueryWrapper<>();

            List<CwPayOrderDetail> orderDetailList = cwPayOrderDetailService.list(queryWrapper);

            if (orderDetailList == null || orderDetailList.size() == 0)  {
                log.warning("--------该结算记录对应的支付订单流水明细查询无。");
                continue;
            }

            for (CwPayOrderDetail orderDetail : orderDetailList) {

                // add by fl 20180524 增加金融服务的场景 start
                if (orderDetail.getCanClearingAmount() == null
                        || BigdecimalUtils.isEqualInTwoBigdecimal(orderDetail.getCanClearingAmount(), BigDecimal.ZERO)) {
                    // 商户可结算金额为空或者=0的时候，无需结算
                    log.warning("--------该明细无商户可结算金额，无需结算，处理跳过。");
                    continue;
                }
                // add by fl 20180524 增加金融服务的场景 end

                // 2-1、企业账户更新（结算入账处理，包括企业账户流水的结算状态更新）
                this.updateBalanceInConfirmClearing(orderDetail);
                log.warning("--------企业账户及账户流水明细更新完成。");
                // 2-2、更新对应的业务订单状态(充值提现申请表和收款计划表)
                this.updateBusinessOrderInConfirmClearing(orderDetail);
                log.warning("--------业务订单状态更新完成。");

            }

            // 3、************ 更新对应的支付订单信息状态为已结算
            this.updatePayOrderInConfirmClearing(orderDetailList.get(0).getPayOrderId());

            log.warning("--------支付订单结算状态更新完成。");

            // 4、************ 更新选中的结算记录的结算状态(从未确认更改为已确认)
            CwClearing clearingForUpdate = new CwClearing();
            clearingForUpdate.setId(clearingItemId);
            // 结算确认状态（2：已确认）
            clearingForUpdate.setClearingConfirmState(ClearingConfirmStateEnum.YQR.getIndex());
            // 结算确认人
            clearingForUpdate.setClearingConfirmUserId(this.tokenService.getLoginUser().getUserid());
            // 结算确认时间
            clearingForUpdate.setClearingConfirmDate(new Date());

            clearingForUpdate.setUpdateUserid(this.tokenService.getLoginUser().getUserid());
            clearingForUpdate.setUpdateTime(new Date());

            // 更新结算表
            this.updateById(clearingForUpdate);

            log.warning("--------结算表更新完成。");

        }

        log.info("confirmClearing确认结算处理 End.");
    }



    /**
     * 结算确认的时候，企业账户更新（结算入账处理）
     * @param orderDetail
     */
    private void updateBalanceInConfirmClearing(CwPayOrderDetail orderDetail) {

        log.info("updateBalanceInConfirmClearing结算确认的时候，企业账户更新处理 Start...");

        // 目前业务中，入金的业务包括企业充值和企业收款即租客支付费用（金融相关业务的结算在前面已经过滤了一遍，都这里的理论上都是需要结算的费用）
        log.info("----请求参数："+JSON.toJSONString(orderDetail));

        if (OperationTypeEnum.CZ.getIndex() == orderDetail.getBusinessOrderType()
                || OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {

            // 入账金额
            BigDecimal confirmAmount = orderDetail.getBusinessOrderAmount();

            // 1、恢复企业的可提现余额，减少对应的冻结金额
            // 1-1、查询商户账号信息
            MCompanyAccount companyAccountOption = new MCompanyAccount();
            companyAccountOption.setBusinessId(orderDetail.getBusinessId());
            companyAccountOption.setDelFlg(0);
            QueryWrapper<MCompanyAccount> queryWrap = new QueryWrapper<MCompanyAccount>(companyAccountOption);

            MCompanyAccount companyAccount = this.companyAccountService.getOne(queryWrap);

            if (companyAccount == null) {
                log.warning("----当前商户的企业账户信息查询不存在，商户账户更新跳过。商户ID："+orderDetail.getBusinessId());
                return;
            }

            // 1-2、更新商户账户余额
            MCompanyAccount companyAccountForUpdate = new MCompanyAccount();
            companyAccountForUpdate.setId(companyAccount.getId());
            // 可用余额
            companyAccountForUpdate.setCashableAmount(this.amountSum(companyAccount.getCashableAmount(), confirmAmount));
            // 冻结余额（不可使用余额）
            companyAccountForUpdate.setFrozenAmount(this.amountSub(companyAccount.getFrozenAmount(), confirmAmount));

            companyAccountForUpdate.setUpdateUserid(this.tokenService.getLoginUser().getUserid());
            companyAccountForUpdate.setUpdateTime(new Date());

            // 更新商户账户余额信息
            this.companyAccountService.updateById(companyAccountForUpdate);

            log.info("----更新商户账户余额完成，更新数据("+JSON.toJSONString(companyAccountForUpdate)+").");

            // 2、更新该笔企业账户流水对应的结算状态(balance表)
            if (OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {
                // 目前充值只有成功未成功的状态，没有管理结算状态。  租客交费有结算状态，故业务收款的时候，需要更新账户流水状态

                // 2-1、查询对应的账户明细流水记录
                // 查询商户账号信息
                CwBalance cwBalanceOption = new CwBalance();
                // 商户ID
                cwBalanceOption.setBusinessId(orderDetail.getBusinessId());
                // 收支类型：收入
                cwBalanceOption.setBalanceType(BalanceTypeEnum.SR.getIndex());
                // 操作类型：收款
                cwBalanceOption.setOperationType(OperationTypeEnum.SK.getIndex());
                // 业务订单ID
                cwBalanceOption.setYwOrderId(orderDetail.getBusinessOrderPlanId());
                cwBalanceOption.setDelFlg(0);
                QueryWrapper<CwBalance> queryBalanceWrap = new QueryWrapper<CwBalance>(cwBalanceOption);

                CwBalance balanceEntity = this.cwBalanceService.getOne(queryBalanceWrap);

                if (balanceEntity == null) {
                    log.warning("----当前结算审核数据对应的企业账户Balance明细信息查询不存在，商户账户明细更新跳过。查询条件："+JSON.toJSONString(cwBalanceOption));
                    return;
                }

                // 2-2、企业账户明细更新
                CwBalance cwBalanceForUpdate = new CwBalance();
                cwBalanceForUpdate.setId(balanceEntity.getId());
                cwBalanceForUpdate.setStatusCode(DzStateEnum.YJS.getIndex());  // 已结算
                cwBalanceForUpdate.setStatusName(DzStateEnum.YJS.getName());

                cwBalanceForUpdate.setUpdateUserid(this.tokenService.getLoginUser().getUserid());
                cwBalanceForUpdate.setUpdateTime(new Date());

                this.cwBalanceService.updateById(cwBalanceForUpdate);

                log.info("----更新企业账户Balance明细完成，更新数据("+JSON.toJSONString(cwBalanceForUpdate)+").");
            }

        }

        log.info("updateBalanceInConfirmClearing结算确认的时候，企业账户更新处理 End.");

    }



    /**
     * 结算确认的时候，更新对应的业务订单状态(充值提现申请表和收款计划表)
     * @param orderDetail
     */
    private void updateBusinessOrderInConfirmClearing(CwPayOrderDetail orderDetail) {

        log.info("updateBusinessOrderInConfirmClearing结算确认的时候，更新对应的业务订单状态处理 Start...");

        // 充值的时候，更新充值申请
        if (OperationTypeEnum.CZ.getIndex() == orderDetail.getBusinessOrderType()) {

            CwCztxApply updateEntity = new CwCztxApply();
            updateEntity.setId(orderDetail.getBusinessOrderPlanId());
            // 到账时间（提现的时候到账时间，充值的时候结算到账时间）
            updateEntity.setDzDate(new Date());

            updateEntity.setUpdateUserid(this.tokenService.getLoginUser().getUserid());
            updateEntity.setUpdateTime(new Date());

            // 更新充值提现申请信息表
            this.cwCztxApplyService.updateById(updateEntity);

            log.info("----更新数据("+JSON.toJSONString(updateEntity)+").");

        } else if (OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {
            // 收款的时候，更新对应收款计划状态
            // --------------- 收款计划中暂时无状态更新 ---------------
        }

        log.info("updateBusinessOrderInConfirmClearing结算确认的时候，更新对应的业务订单状态处理 End.");
    }


    /**
     * 结算确认的时候，更新对应的支付订单信息状态为已结算
     * @param payOrderId
     */
    private void updatePayOrderInConfirmClearing(Long payOrderId) {

        log.info("updatePayOrderInConfirmClearing结算确认的时候，更新对应的支付订单信息状态为已结算处理 Start...");

        CwPayOrder updateEntity = new CwPayOrder();
        updateEntity.setId(payOrderId);
        // 对账状态：已结算
        updateEntity.setDzState(DzStateEnum.YJS.getIndex());

        updateEntity.setUpdateUserid(this.tokenService.getLoginUser().getUserid());
        updateEntity.setUpdateTime(new Date());

        // 更新支付订单表
        this.cwPayOrderService.updateById(updateEntity);

        log.info("updatePayOrderInConfirmClearing结算确认的时候，更新对应的支付订单信息状态为已结算处理 End.");
    }


    /**
     * 两个BigDecimal 求和
     * @param //cashableAmount
     * @param //confirmAmount
     * @return
     */
    private BigDecimal amountSum(BigDecimal obj1, BigDecimal obj2) {
        if (obj1 == null && obj2 == null) return BigDecimal.ZERO;
        if (obj1 == null) {
            return obj2;
        } else if (obj2 == null) {
            return obj1;
        } else {
            return obj1.add(obj2);
        }
    }

    /**
     * 返回obj1 - obj2
     * 减完的结果>=0，小于0的时候，全部按0返回
     * @param obj1
     * @param obj2
     * @return
     */
    private BigDecimal amountSub(BigDecimal obj1, BigDecimal obj2) {

        if (obj1 == null) {
            return BigDecimal.ZERO;
        }

        if (obj2 == null) {
            return obj1;
        } else {
            BigDecimal subResult = obj1.subtract(obj2);
            if (subResult.compareTo(BigDecimal.ZERO) < 0) {
                return BigDecimal.ZERO;
            } else {
                return subResult;
            }
        }
    }
}




